﻿//--------------------------------------------------------------------------------------------------------------------------------------------------------
// <copyright file="SigningInSteps.cs">
//     Copyright © 2010 Oli Francis
//     This source code is subject to the terms and conditions of the MIT license. A copy of the license can be found in the license.txt 
//     file at the root of this distribution. By using this source code in any fashion, you are agreeing to be bound by the terms of the MIT License. 
//     You must not remove this notice from the software.
// </copyright>
// <author>Oli</author>
//-------------------------------------------------------------------------------------------------------------------------------------------------------

namespace TeamBrain.Tests.StepDefinitions
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web.Mvc;

    using Moq;

    using NUnit.Framework;

    using TeamBrain.Domain.Services.Exceptions;
    using TeamBrain.Domain.Services.Security;
    using TeamBrain.Web.Controllers;

    using TechTalk.SpecFlow;

    [Binding]
    [StepScope(Feature = "Signing In")]
    public class SigningInSteps
    {
        #region Private fields

        private Mock<ISecurityService> securityService;
        private SecurityController controller;
        private ActionResult result;

        #endregion

        #region SetUp

        [BeforeScenario]
        public void Initialize()
        {
            this.securityService = new Mock<ISecurityService>();
            this.controller = new SecurityController(this.securityService.Object);

            ScenarioContext.Current["Email"] = string.Empty;
            ScenarioContext.Current["Password"] = string.Empty;
            ScenarioContext.Current["RememberMe"] = false;
        }

        #endregion

        #region Given

        [Given(@"I have entered an email address that doesn't exist")]
        public void GivenIHaveEnteredAnEmailAddressThatDoesntExist()
        {
            ScenarioContext.Current["Email"] = "oli@doesnotexist.com";

            this.securityService
                .Setup(s => s.AttemptSignIn(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
                .Returns(SignInOutcome.CredentialsIncorrect);
        }

        [Given(@"I have entered an email address that is valid")]
        public void GivenIHaveEnteredAnEmailAddressThatIsValid()
        {
            ScenarioContext.Current["Email"] = "oli@valid.com";
        }

        [Given(@"I have entered a password")]
        public void GivenIHaveEnteredAPassword()
        {
            ScenarioContext.Current["Password"] = "password";
        }

        [Given(@"I have entered a password that is valid")]
        public void GivenIHaveEnteredAPasswordThatIsValid()
        {
            ScenarioContext.Current["Password"] = "password";
            
            this.securityService
                .Setup(s => s.AttemptSignIn(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
                .Returns(SignInOutcome.Success);
        }

        [Given(@"I have entered a password that is incorrect")]
        public void GivenIHaveEnteredAPasswordThatIsIncorrect()
        {
            ScenarioContext.Current["Password"] = "bad!";

            this.securityService
                .Setup(s => s.AttemptSignIn(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
                .Returns(SignInOutcome.CredentialsIncorrect);
        }

        [Given(@"I have entered an invalid password 4 times previously")]
        public void GivenIHaveEnteredAnInvalidPassword4TimesPreviously()
        {
            this.securityService
                .Setup(s => s.AttemptSignIn(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
                .Returns(SignInOutcome.AccountLocked);
        }

        [Given(@"My account has been locked out")]
        public void GivenMyAccountHasBeenLockedOut()
        {
            this.securityService
                .Setup(s => s.AttemptSignIn(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
                .Returns(SignInOutcome.AccountLocked);
        }

        [Given(@"At least ten minutes have passed since my last failed signin attempt")]
        public void GivenAtLeastTenMinutesHavePassedSinceMyLastFailedSigninAttempt()
        {
            this.securityService
                .Setup(s => s.AttemptSignIn(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
                .Returns(SignInOutcome.Success);
        }

        [Given(@"My account has been disabled")]
        public void GivenMyAccountHasBeenDisabled()
        {
            this.securityService
                .Setup(s => s.AttemptSignIn(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
                .Returns(SignInOutcome.AccountDisabled);            
        }

        #endregion

        #region When

        [When(@"I visit the sign-in page")]
        public void WhenIVisitTheSignInPage()
        {
            this.result = this.controller.SignIn();
        }

        [When(@"I press the sign in button")]
        public void WhenIPressTheSignInButton()
        {
            var email = (string)ScenarioContext.Current["Email"];
            var password = (string)ScenarioContext.Current["Password"];
            var rememberMe = (bool)ScenarioContext.Current["RememberMe"];

            this.result = this.controller.SignIn(email, password, rememberMe);
        }

        #endregion

        #region Then

        [Then(@"I see a form allowing me to enter my credentials")]
        public void ThenISeeAFormAllowingMeToEnterMyCredentials()
        {
            var view = this.result as ViewResult;
            Assert.IsNotNull(view);
            Assert.AreEqual("SignIn", view.ViewName);
        }

        [Then(@"I see an error message against (.*)")]
        public void ThenISeeAnErrorMessageAgainstX(string field)
        {
            var view = this.result as ViewResult;
            Assert.IsNotNull(view);
            Assert.IsFalse(view.ViewData.ModelState.IsValidField(field));
        }

        [Then(@"I see a generic message saying that my details didn't match")]
        public void ThenISeeAGenericMessageSayingThatMyDetailsDidntMatch()
        {
            var view = this.result as ViewResult;
            Assert.IsNotNull(view);
            Assert.IsFalse(view.ViewData.ModelState.IsValidField("signin"));
        }

        [Then(@"I see an error saying my account is locked")]
        public void ThenISeeAnErrorSayingMyAccountIsLocked()
        {
            var view = this.result as ViewResult;
            Assert.IsNotNull(view);
            Assert.IsFalse(view.ViewData.ModelState.IsValidField("signin"));
        }

        [Then(@"I see an error saying my account is disabled")]
        public void ThenISeeAnErrorSayingMyAccountIsDisabled()
        {
            var view = this.result as ViewResult;
            Assert.IsNotNull(view);
            Assert.IsFalse(view.ViewData.ModelState.IsValidField("signin"));
        }
        
        [Then(@"I get redirected to my profile page")]
        public void ThenIGetRedirectedToMyProfilePage()
        {
            var redirect = this.result as RedirectToRouteResult;
            Assert.IsNotNull(redirect);
        }
        
        #endregion
    }
}
